/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_lru.h"
#include "ak_gears.h"

static 	_t_sysMSlot 	_gTest_Lru_MSlot;
static 	_t_sysMPool 	_gTest_Lru_MPool;
static	_t_sysMHeap 	_gTest_Lru_MHeap;

static 	_t_sysLruCt  	_gTest_LruCt;
static 	_t_sysKLMem  	_gTest_KLMem;
static 	_t_sysKLFunc 	_gTest_KLFunc;
static 	time_t 			_gTest_LruCurrent;

#define _TEST_LRU_CNT 	0X1000
static 	int 			_gTest_LruKey[_TEST_LRU_CNT];
static 	_t_sysLruCi *	_gTest_LruCi[_TEST_LRU_CNT];


static 	int 	_LruTest_KeyComp(_t_rbnode * node1, _t_rbnode * node2)
{
	unsigned long long   key1;
	unsigned long long   key2;

	key1 = *((unsigned long long *)((_O_PARENT(_t_sysLruCi, mi.kNode, node1))->pKey));
	key2 = *((unsigned long long *)((_O_PARENT(_t_sysLruCi, mi.kNode, node2))->pKey));

	if(key1 > key2){
		return _TREE_GREAT;
	}else if(key1 < key2){
		return _TREE_LESS;
	}

	return _TREE_EQUAL;
}

static 	int 	_LruTest_Free(_t_sysLruCt * pCt, _t_sysLruCi * pCi)
{
	_t_sysMPool * pPool;

	pPool = &_gTest_Lru_MPool;
	MPool_FreeSi(pPool, pCi);
	return 0;
}


static 	int 	_LruTest_ExpireQ(_t_sysLruCt * pCt, _t_blist * pQueue)
{
	_t_sysMPool * pPool;

	pPool = &_gTest_Lru_MPool;
	MPool_FreeNi(pPool, pQueue);
	return 0;
}

/* 1. Construct an LruCt */

static 	int _LruTest_Init(void)
{
	_t_sysLruCt * pCt;

	_t_sysKLMem * pKLMem;
	_t_sysKLFunc* pKLFunc;
	
	_t_sysMPool * pPool;
	_t_sysMHeap * pHeap;
	_t_sysMSlot * pSlot;

	int i;
	/* Init the Mem */
	pHeap = &_gTest_Lru_MHeap;
	pPool = &_gTest_Lru_MPool;
	pSlot = &_gTest_Lru_MSlot;
	
	MHeap_Init(pHeap, sizeof(_t_sysLruCi));
	MPool_Init(pPool, pHeap,	
				(_TEST_LRU_CNT * 2 * sizeof(_t_sysLruCi)),	sizeof(_t_sysLruCi), 
				1,	 1, MPOOL_T_SIMP);
	/* Init the Slot */
	MPOOL_SET_SLOT(pPool, pSlot);
	MSlot_Init(pSlot, pPool, 0, (unsigned int)(sizeof(_t_sysLruCi)));

	/* Init the KL */
	pKLMem = &_gTest_KLMem;
	pKLFunc= &_gTest_KLFunc;
	
	_KLMEM_INIT(pKLMem, NULL, pHeap, NULL);
	_KLFUNC_INIT(pKLFunc, 
		_LruTest_KeyComp, 
		NULL, NULL, 
		_LruTest_Free, _LruTest_ExpireQ);

	/* Init the Ct */
	_gTest_LruCurrent = 0;
	pCt = &_gTest_LruCt;
	_SLRU_CT_INIT(pCt, &_gTest_KLMem, &_gTest_KLFunc, 0, &_gTest_LruCurrent);

	/* Init the Key */
	for(i=0; i<_TEST_LRU_CNT; i++){
		_gTest_LruKey[i] = i;
	}
	return 0;
}

/* 2. Add / Del /Replace LruCi */
static 	int 	_LruTest_Add(void)
{
	_t_sysLruCt * pCt;
	_t_sysLruCi * pCi;
	_t_sysMPool * pPool;

	int i;

	pCt = &_gTest_LruCt;
	pPool = &_gTest_Lru_MPool;
	for(i=0; i<_TEST_LRU_CNT; i++){
		pCi = (_t_sysLruCi *)MPool_AllocSi(pPool);
		if(pCi){
			pCi->pKey = (_gTest_LruKey + i);
			pCi->lKey = sizeof(int);
			pCi->ti.expire = i;
			_gTest_LruCi[i] = pCi;
			SLru_Add(pCt, pCi);
		}
	}
	return 0;
}

static 	int 	_LruTest_Del(void)
{
	_t_sysLruCt * pCt;
	_t_sysLruCi * pCi;
	_t_sysMPool * pPool;

	int i;

	pCt = &_gTest_LruCt;
	pPool = &_gTest_Lru_MPool;
	for(i=0; i<_TEST_LRU_CNT; i++){
		pCi = _gTest_LruCi[i];
		if(pCi){
			SLru_RmEx(pCt, pCi);
		}
	}
	return 0;
}


static 	int 	_LruTest_Replace(void)
{
	_t_sysLruCt * pCt;
	_t_sysLruCi * pCi;
	_t_sysLruCi * pClea;
	_t_sysMPool * pPool;

	int i;

	pCt = &_gTest_LruCt;
	pPool = &_gTest_Lru_MPool;
	for(i=0; i<_TEST_LRU_CNT; i++){
		pCi = (_t_sysLruCi *)MPool_AllocSi(pPool);
		if(pCi){
			pCi->pKey = (_gTest_LruKey + i);
			pCi->lKey = sizeof(int);
			pCi->ti.expire = i;
			_gTest_LruCi[i] = pCi;
			SLru_Replace(pCt, pCi, &pClea, NULL, 0);
		}
	}
	return 0;
}


static 	int 	_LruTest_Get(void)
{
	_t_sysLruCt * pCt;
	_t_sysLruCi * pCi;
	_t_sysMPool * pPool;

	int i;

	pCt = &_gTest_LruCt;
	pPool = &_gTest_Lru_MPool;
	for(i=0; i<_TEST_LRU_CNT; i++){
		pCi = SLru_Get(pCt, _gTest_LruCi[i], NULL, 0);
		if(pCi != _gTest_LruCi[i]){
			printf("Ci Err: %p - %p\n", pCi, _gTest_LruCi[i]);
		}
	}
	return 0;
}


/* 3. Set the Expire, GC */
static 	int 	_LruTest_Expire(void)
{
	_t_sysLruCt * pCt;
	
	pCt = &_gTest_LruCt;

	_gTest_LruCurrent = SLru_TickStep(_gTest_LruCurrent);
	SLru_Expire(pCt, _gTest_LruCurrent, 8);
	return 0;
}


#define _TEST_MEM_DUMP_BUF 	0X10000
static 	char 			_gTest_MDump[_TEST_MEM_DUMP_BUF];
int 	main(void)
{
	int i, j;
	_t_sysMPool * pPool;
	pPool = &_gTest_Lru_MPool;

	/* Init */
	_LruTest_Init();
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 0: \n%s\n", _gTest_MDump);

	/* Test Add/Replace/Del */
	_LruTest_Add();
	_LruTest_Get();
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 1: \n%s\n", _gTest_MDump);
	
	
	_LruTest_Replace();
	_LruTest_Get();
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 2: \n%s\n", _gTest_MDump);

	_LruTest_Del();
	_LruTest_Get();
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 3: \n%s\n", _gTest_MDump);

	/* Test Expire */
	_LruTest_Add();
	_LruTest_Get();
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 4: \n%s\n", _gTest_MDump);


	for(i=0; i<0X100; i++){
		for(j=0; j<0X10; j++){
			_LruTest_Expire();
		}
		SYS_SLEEP(20);
	}
	MPool_Dump(pPool, _gTest_MDump, _TEST_MEM_DUMP_BUF);
	printf("\nDump 5: \n%s\n", _gTest_MDump);
	return 0;
}
